import binascii
import copy
import csv
import logging
import os
import queue
import re
import sys
import time
from ast import Pass
from ctypes import *
from operator import index
from threading import Thread
from tracemalloc import start

import bincopy
import numpy as np
import pandas as pd
import pytest
from regex import R

import TSMasterAPI

class DB_Variable:
    DT_STR_Network_Name = 0                                       # 获取网络名称
    DT_STR_DBC_FileName = 1                                       # 获取dbc文件名
    DT_INT_Protocol_Type = 2                                      # 获取协议类型,0=CAN; 1=FD; 2=J1939
    DT_INT_3 = 3                                                  # unused
    DT_INT_4 = 4                                                  # unused
    DT_INT_5 = 5                                                  # unused
    DT_INT_6 = 6                                                  # unused
    DT_INT_7 = 7                                                  # unused
    DT_INT_8 = 8                                                  # unused
    DT_INT_9 = 9                                                  # unused
    DT_INT_Signal_List_Count = 10                                 # 获取信号表数量 = db.sgns.count
    DT_INT_CAN_Message_List_Count = 11                            # 获取CAN报文表数量 = db.msgs.count
    DT_INT_CANFD_Message_List_Count = 12                          # 获取CAN FD报文表数量 = db.msgsFD.count
    DT_INT_CANJ1939_Message_List_Count = 13                       # 获取CAN J1939报文表数量 = db.msgsJ1939.count
    DT_INT_Node_List_Count = 14                                   # 获取节点表数量 = db.nodes.count
    DT_INT_EnvVar_List_Count = 15                                 # 获取环境变量表数量 = db.envs.count
    DT_INT_ValTab_List_Count = 16                                 # 获取取值表数量 = db.valtabs.count
    DT_INT_17 = 17                                                # unused
    DT_INT_18 = 18                                                # unused
    DT_INT_19 = 19                                                # unused
    DT_INT_Signal_List_Message_ID = 20                            # 获取信号表中第idx信号所在的报文标识符 db.sgns[idx].message_id
    DT_INT_Signal_List_Value_Type = 21                            # 获取信号表中第idx信号值类型 0-无符号整型 1-有符号整型 2-32位浮点 3-64位浮点
    DT_INT_Signal_List_Is_Motorola = 22                           # 获取信号表中第idx信号是否是Motorola格式,0-Intel格式、1-Motorola格式
    DT_INT_Signal_List_ValTab_Index = 23                          # 获取信号表中第idx信号所带的取值表在取值表列表中的索引
    DT_INT_Signal_List_Mux_Type = 24                              # 获取信号表中第idx信号Mux类型,0-普通信号, 1-multiplexor, 2-multiplexed信号
    DT_INT_Signal_List_Mux_Value = 25                             # 获取信号表中第idx信号作为multiplexor的值
    DT_INT_Signal_List_Layout_Start = 26                          # 获取信号表中第idx信号在报文中的起始位
    DT_INT_Signal_List_Length = 27                                # 获取信号表中第idx信号的信号长度
    DT_DBL_Signal_List_Factor = 28                                # 获取信号表中第idx信号放大因子
    DT_DBL_Signal_List_Offset = 29                                # 获取信号表中第idx信号偏移量
    DT_DBL_Signal_List_InitValue = 30                             # 获取信号表中第idx信号初始值
    DT_DBL_Signal_List_Min = 31                                   # 获取信号表中第idx信号最小值
    DT_DBL_Signal_List_Max = 32                                   # 获取信号表中第idx信号最大值
    DT_STR_Signal_List_Name = 33                                  # 获取信号表中第idx信号名称
    DT_STR_Signal_List_Unit = 34                                  # 获取信号表中第idx信号单位
    DT_STR_Signal_List_Comment = 35                               # 获取信号表中第idx信号注释
    DT_INT_Signal_List_Message_Index = 36                         # 获取信号表中第idx信号所在的报文在报文表中的索引 db.msgs[db.sgns[idx].message_idx]
    DT_INT_Signal_List_Message_Type = 37                          # 获取信号表中第idx信号所在的报文的类型,0=CAN, 1=CANFD, 2=J1939
    DT_STR_Signal_List_Struct = 38                                # 获取信号表中第idx信号全部属性,逗号分隔 db.sgns[idx]
    DT_INT_39 = 39                                                # unused
    DT_INT_CAN_Message_List_Type = 40                             # 获取CAN报文表中第idx报文类型,cftStdCAN = 0, cftExtCAN = 1, cftJ1939 = 2, cftStdCANFD = 3, cftExtCANFD = 4
    DT_INT_CAN_Message_List_DLC = 41                              # 获取CAN报文表中第idx报文数据长度
    DT_INT_CAN_Message_List_ID = 42                               # 获取CAN报文表中第idx报文标识符
    DT_INT_CAN_Message_List_CycleTime = 43                        # 获取CAN报文表中第idx报文周期
    DT_STR_CAN_Message_List_Name = 44                             # 获取CAN报文表中第idx报文名称
    DT_STR_CAN_Message_List_Comment = 45                          # 获取CAN报文表中第idx报文注释
    DT_INT_CAN_Message_List_TX_Node_Index = 46                    # 获取CAN报文表中第idx报文对应的发送节点的索引
    DT_INT_CAN_Message_List_Owned_Signal_List_Count = 47          # 获取CAN报文表中第idx报文拥有的信号数量 db.msgs[idx].sgns.count
    DT_INT_CAN_Message_List_Owned_Signal_List_Signal_Index = 48   # 获取CAN报文表中第idx报文中第subidx信号在信号表中的索引 db.sgns[db.sgns.indexof(db.msgs[idx].sgns[subidx])]
    DT_STR_CAN_Message_List_Struct = 49                           # 获取CAN报文表中第idx报文全部属性,逗号分隔 db.msgs[idx]
    DT_INT_50 = 50                                                # unused
    DT_INT_51 = 51                                                # unused
    DT_INT_52 = 52                                                # unused
    DT_INT_53 = 53                                                # unused
    DT_INT_54 = 54                                                # unused
    DT_INT_55 = 55                                                # unused
    DT_INT_56 = 56                                                # unused
    DT_INT_57 = 57                                                # unused
    DT_INT_58 = 58                                                # unused
    DT_INT_59 = 59                                                # unused
    DT_INT_CANFD_Message_List_Type = 60                           # 获取CANFD报文表中第idx报文类型,cftStdCAN = 0, cftExtCAN = 1, cftJ1939 = 2, cftStdCANFD = 3, cftExtCANFD = 4
    DT_INT_CANFD_Message_List_DLC = 61                            # 获取CANFD报文表中第idx报文数据长度
    DT_INT_CANFD_Message_List_ID = 62                             # 获取CANFD报文表中第idx报文标识符
    DT_INT_CANFD_Message_List_CycleTime = 63                      # 获取CANFD报文表中第idx报文周期
    DT_STR_CANFD_Message_List_Name = 64                           # 获取CANFD报文表中第idx报文名称
    DT_STR_CANFD_Message_List_Comment = 65                        # 获取CANFD报文表中第idx报文注释
    DT_INT_CANFD_Message_List_TX_Node_Index = 66                  # 获取CANFD报文表中第idx报文对应的发送节点的索引
    DT_INT_CANFD_Message_List_Owned_Signal_List_Count = 67        # 获取CANFD报文表中第idx报文拥有的信号数量 db.msgs[idx].sgns.count
    DT_INT_CANFD_Message_List_Owned_Signal_List_Signal_Index = 68 # 获取CANFD报文表中第idx报文中第subidx信号在信号表中的索引 db.sgns[db.sgns.indexof(db.msgs[idx].sgns[subidx])]
    DT_INT_CANFD_Message_List_BRS = 69                            # 获取CANFD报文表中第idx报文BRS,0-No BRS、1-BRS
    DT_STR_CANFD_Message_List_Struct = 70                         # 获取CANFD报文表中第idx报文全部属性,逗号分隔 db.msgs[idx]
    DT_INT_71 = 71                                                # unused
    DT_INT_72 = 72                                                # unused
    DT_INT_73 = 73                                                # unused
    DT_INT_74 = 74                                                # unused
    DT_INT_75 = 75                                                # unused
    DT_INT_76 = 76                                                # unused
    DT_INT_77 = 77                                                # unused
    DT_INT_78 = 78                                                # unused
    DT_INT_79 = 79                                                # unused
    DT_INT_J1939_Message_List_Type = 80                           # 获取J1939报文表中第idx报文类型,cftStdCAN = 0, cftExtCAN = 1, cftJ1939 = 2, cftStdCANFD = 3, cftExtCANFD = 4
    DT_INT_J1939_Message_List_DLC = 81                            # 获取J1939报文表中第idx报文数据长度
    DT_INT_J1939_Message_List_ID = 82                             # 获取J1939报文表中第idx报文标识符
    DT_INT_J1939_Message_List_CycleTime = 83                      # 获取J1939报文表中第idx报文周期
    DT_STR_J1939_Message_List_Name = 84                           # 获取J1939报文表中第idx报文名称
    DT_STR_J1939_Message_List_Comment = 85                        # 获取J1939报文表中第idx报文注释
    DT_INT_J1939_Message_List_TX_Node_Index = 86                  # 获取J1939报文表中第idx报文对应的发送节点的索引
    DT_INT_J1939_Message_List_Owned_Signal_List_Count = 87        # 获取J1939报文表中第idx报文拥有的信号数量 db.msgs[idx].sgns.count
    DT_INT_J1939_Message_List_Owned_Signal_List_Signal_Index = 88 # 获取J1939报文表中第idx报文中第subidx信号在信号表中的索引 db.sgns[db.sgns.indexof(db.msgs[idx].sgns[subidx])]
    DT_STR_J1939_Message_List_Struct = 89                         # 获取CAN报文表中第idx报文全部属性,逗号分隔 db.msgs[idx]
    DT_INT_90 = 90                                                # unused
    DT_INT_91 = 91                                                # unused
    DT_INT_92 = 92                                                # unused
    DT_INT_93 = 93                                                # unused
    DT_INT_94 = 94                                                # unused
    DT_INT_95 = 95                                                # unused
    DT_INT_96 = 96                                                # unused
    DT_INT_97 = 97                                                # unused
    DT_INT_98 = 98                                                # unused
    DT_INT_99 = 99                                                # unused
    DT_INT_Node_List_Address = 100                                # 获取节点表中第idx节点地址,默认为0
    DT_STR_Node_List_Name = 101                                   # 获取节点表中第idx节点名称
    DT_STR_Node_List_Comment = 102                                # 获取节点表中第idx节点注释
    DT_INT_Node_List_TX_CAN_Message_List_Count = 103              # 获取节点表中第idx节点所发送的CAN报文数量 db.nodes[idx].txmsgs.count
    DT_INT_Node_List_TX_CAN_Message_List_Message_Index = 104      # 获取节点表中第idx节点所发送的subidx报文在CAN报文表中的索引 db.msgs[db.msgs.indexof(db.nodes[idx].txmsgs[subidx])]
    DT_INT_Node_List_RX_CAN_Message_List_Count = 105              # 获取节点表中第idx节点所接收的CAN报文数量
    DT_INT_Node_List_RX_CAN_Message_List_Message_Index = 106      # 获取节点表中第idx节点所接收的subidx报文在CAN报文表中的索引
    DT_INT_Node_List_TX_FD_Message_List_Count = 107               # 获取节点表中第idx节点所发送的FD报文数量 db.nodes[idx].txmsgs.count
    DT_INT_Node_List_TX_FD_Message_List_Message_Index = 108       # 获取节点表中第idx节点所发送的subidx报文在FD报文表中的索引 db.msgs[db.msgs.indexof(db.nodes[idx].txmsgs[subidx])]
    DT_INT_Node_List_RX_FD_Message_List_Count = 109               # 获取节点表中第idx节点所接收的FD报文数量
    DT_INT_Node_List_RX_FD_Message_List_Message_Index = 110       # 获取节点表中第idx节点所接收的subidx报文在FD报文表中的索引
    DT_INT_Node_List_TX_J1939_Message_List_Count = 111            # 获取节点表中第idx节点所发送的J1939报文数量 db.nodes[idx].txmsgs.count
    DT_INT_Node_List_TX_J1939_Message_List_Message_Index = 112    # 获取节点表中第idx节点所发送的subidx报文在J1939报文表中的索引 db.msgs[db.msgs.indexof(db.nodes[idx].txmsgs[subidx])]
    DT_INT_Node_List_RX_J1939_Message_List_Count = 113            # 获取节点表中第idx节点所接收的J1939报文数量
    DT_INT_Node_List_RX_J1939_Message_List_Message_Index = 114    # 获取节点表中第idx节点所接收的subidx报文在J1939报文表中的索引
    DT_INT_Node_List_TX_Signal_List_Count = 115                   # 获取节点表中第idx节点所发送的信号数量
    DT_INT_Node_List_TX_Signal_List_Signal_Index = 116            # 获取节点表中第idx节点所发送的subidx信号在信号表中的索引
    DT_INT_Node_List_RX_Signal_List_Count = 117                   # 获取节点表中第idx节点所接收的信号数量
    DT_INT_Node_List_RX_Signal_List_Signal_Index = 118            # 获取节点表中第idx节点所接收的subidx信号在信号表中的索引
    DT_STR_Node_List_Struct = 119                                 # 获取节点表中第idx节点全部属性,逗号分隔 db.nodes[idx]
    DT_INT_120 = 120                                              # unused
    DT_INT_121 = 121                                              # unused
    DT_INT_122 = 122                                              # unused
    DT_INT_123 = 123                                              # unused
    DT_INT_124 = 124                                              # unused
    DT_INT_125 = 125                                              # unused
    DT_INT_126 = 126                                              # unused
    DT_INT_127 = 127                                              # unused
    DT_INT_128 = 128                                              # unused
    DT_INT_129 = 129                                              # unused
    DT_INT_EnvVar_List_Value_Type = 130                           # 获取环境变量表中第idx环境变量值类型,0-整型、1-浮点、2-字符串、3-数据
    DT_DBL_EnvVar_List_MIN = 131                                  # 获取环境变量表中第idx环境变量最小值
    DT_DBL_EnvVar_List_MAX = 132                                  # 获取环境变量表中第idx环境变量最大值
    DT_DBL_EnvVar_List_Init_Value = 133                           # 获取环境变量表中第idx环境变量初始值
    DT_STR_EnvVar_List_Name = 134                                 # 获取环境变量表中第idx环境变量名称
    DT_STR_EnvVar_List_Unit = 135                                 # 获取环境变量表中第idx环境变量单位
    DT_STR_EnvVar_List_Comment = 136                              # 获取环境变量表中第idx环境变量注释
    DT_STR_EnvVar_List_Struct = 137                               # 获取环境变量表中第idx环境变量全部属性,逗号分隔 db.EnvVars[idx]
    DT_INT_138 = 138                                              # unused
    DT_INT_139 = 139                                              # unused
    DT_INT_ValTab_List_Item_List_Count = 140                      # 获取取值表中第idx取值表所包含的值数量
    DT_INT_ValTab_List_Item_List_Name = 141                       # 获取取值表中第idx取值表名称
    DT_DBL_ValTab_List_Item_List_Value = 142                      # 获取取值表中第idx取值表中第subidx的值
    DT_STR_ValTab_List_Struct = 143                               # 获取取值表中第idx取值表全部属性,逗号分隔 db.ValTabs[idx]

# q=queue.Queue(10000)
# obj_HIL_q=queue.Queue(10000)

def On_CAN_EVENT(OBJ, ACAN):
    if (ACAN.contents.FIdentifier == 0x777 and ACAN.contents.FIdxChn == 0):
        logging.info("CAN回调接收成功")
        for i in ACAN.contents.FData:
            print('%#x' % i, end=' ')
        logging.info('')
    CAN_data = pd.Series({'AIdxChn':ACAN.contents.FIdxChn,
                            'AIsTx':0,
                            'AIsRemote':0,
                            'AIsExtended':ACAN.contents.FProperties,
                            'AIsError':0,
                            'ADLC':ACAN.contents.FDLC,
                            'AIdentifier':ACAN.contents.FIdentifier,
                            'ATimeUs':ACAN.contents.FTimeUs/1000000.0,
                            'ADatas':ACAN.contents.FData}) 
OnCANevent = TSMasterAPI.OnTx_RxFUNC_CAN(On_CAN_EVENT)

def On_CANFD_EVENT(OBJ, ACAN):
    if (ACAN.contents.FIdentifier == 0x666 and ACAN.contents.FIdxChn == 0):
        # print("CANFD 0x666 回调接收成功")
        # for i in ACAN.contents.FData:
        #     print('%#x' % i, end=' ')
        # print('')
        pass
    if (ACAN.contents.FIdentifier == 0x777 and ACAN.contents.FIdxChn == 0):
        # print("CAN 0x777 回调接收成功")
        # for i in ACAN.contents.FData:
        #     print('%#x' % i, end=' ')
        # print('')
        pass
    # CAN_data = pd.Series({'AIdxChn':ACAN.contents.FIdxChn,
    #                         'AIsTx':0,
    #                         'AIsExtended':ACAN.contents.FProperties,
    #                         'AIsError':0,
    #                         'AIsEDL':0,
    #                         'AIsBRS':ACAN.contents.FFDProperties,
    #                         'AIsESI':0,
    #                         'ADLC':ACAN.contents.FDLC,
    #                         'AIdentifier':ACAN.contents.FIdentifier,
    #                         'ATimeUs':ACAN.contents.FTimeUs/1000000.0,
    #                         'ADatas':ACAN.contents.FData})
    # try:
    #     q.put(CAN_data)
    # except queue.Full:
    #     q.queue.clear()
    #     print('queue.Full') 
    pass   
OnCANFDevent = TSMasterAPI.OnTx_RxFUNC_CANFD(On_CANFD_EVENT)

class TSCAN(object):
    def __init__(self,drive_type = 'USE_TS_VIRTUAL_DEVICE',
                configure_baudrate = {'CAN_Type':'CANFD','ArbRate':500,'DataRate':2000,'TermResistor':True},
                ChannelIndex = TSMasterAPI.CHANNEL_INDEX.CHN1,
                APP_NAME = "Auto_TS_Test",
                totle_channel_count = 1
                ):
        error_code = 0
        self.drive_type = drive_type
        self.configure_baudrate = configure_baudrate
        self.ChannelIndex = ChannelIndex
        self.APP_NAME = APP_NAME.encode("utf-8")
        self.EnableNode= []
        self.FrameData = [0,0,0,0,0,0,0,0]
        # self.bufferszie = copy.copy(c_uint32(100000))
        self.bufferszie = copy.deepcopy(c_uint32(10000))

        # init TS CAN variable
        self.cFD = TSMasterAPI.TLIBCANFD()
        self.c = TSMasterAPI.TLIBCAN()

        self.cFD_buffer=[]
        for i in range(10000):
            cfd = TSMasterAPI.TLIBCANFD()
            self.cFD_buffer.append(cfd)
        self.c_buffer=[]
        for i in range(10000):
            c = TSMasterAPI.TLIBCAN()
            self.c_buffer.append(c)

        self.idDBC = c_uint32(0)  # 加载dbc句柄
        self.obj = c_int32(0)
        self.read_frame_ALl_data = pd.DataFrame()

        # 初始化函数（是否使能fifo,是否激活极速模式）
        if 0 == TSMasterAPI.dll.initialize_lib_tsmaster(self.APP_NAME):
            logging.info('initialize_lib_tsmaster success ')
        else:
            logging.warning('initialize_lib_tsmaster error ' )
        # if 0 == TSMasterAPI.dll.tsapp_set_turbo_mode(True):
        #     print('set_turbo_mode True success ')
        # else:
        #     print('set_turbo_mode True error')

        # set CAN channel count to 2
        if 0 == TSMasterAPI.tsapp_set_can_channel_count(totle_channel_count):
            logging.info('set_can_channel_coun to  {0}'.format(totle_channel_count))
        else:
            logging.warning('set_can_channel_coun error: {0} '.format(totle_channel_count) )
        
        # map application channel 1 to hw index 0, channel 0 of Vector virtual channel
        m = TSMasterAPI.TLIBTSMapping()
        m.FAppName = self.APP_NAME
        m.FAppChannelIndex = self.ChannelIndex.value
        m.FAppChannelType = TSMasterAPI.TLIBApplicationChannelType.APP_CAN.value
        m.FHWIndex = 0
        m.FHWChannelIndex = self.ChannelIndex.value
        
        if self.drive_type == 'USE_XL_VIRTUAL_DEVICE':
            m.FHWDeviceType = TSMasterAPI.TLIBBusToolDeviceType.XL_USB_DEVICE.value
            m.FHWDeviceSubType = 1
        elif self.drive_type == 'USE_XL_VN1630_DEVICE':
            m.FHWDeviceType = TSMasterAPI.TLIBBusToolDeviceType.XL_USB_DEVICE.value
            m.FHWDeviceSubType = 57
        elif self.drive_type == 'USE_XL_VN1640_DEVICE':
            m.FHWDeviceType = TSMasterAPI.TLIBBusToolDeviceType.TS_USB_DEVICE.value
            m.FHWDeviceSubType = 59
        elif self.drive_type == 'USE_TS_VIRTUAL_DEVICE':
            m.FHWDeviceType = TSMasterAPI.TLIBBusToolDeviceType.TS_TCP_DEVICE.value
            m.FHWDeviceSubType = -1
        elif self.drive_type == 'USE_TS_TC1014_DEVICE':
            m.FHWDeviceType = TSMasterAPI.TLIBBusToolDeviceType.TS_USB_DEVICE.value
            m.FHWDeviceSubType = TSMasterAPI.TLIB_TS_Device_Sub_Type.TC1014.value
        elif self.drive_type == 'USE_TS_TC1016_DEVICE':
            m.FHWDeviceType = TSMasterAPI.TLIBBusToolDeviceType.TS_USB_DEVICE.value
            m.FHWDeviceSubType = TSMasterAPI.TLIB_TS_Device_Sub_Type.TC1016.value
        elif self.drive_type == 'USE_TS_TC1011_DEVICE':
            m.FHWDeviceType = TSMasterAPI.TLIBBusToolDeviceType.TS_USB_DEVICE.value
            m.FHWDeviceSubType = TSMasterAPI.TLIB_TS_Device_Sub_Type.TC1011.value
        elif self.drive_type == 'USE_TS_TC1013_DEVICE':
            m.FHWDeviceType = TSMasterAPI.TLIBBusToolDeviceType.TS_USB_DEVICE.value
            m.FHWDeviceSubType = TSMasterAPI.TLIB_TS_Device_Sub_Type.TC1013.value
        
        m.FHWDeviceName = self.drive_type.encode("UTF8")
        r = TSMasterAPI.tsapp_set_mapping(m)
        if 0 == r:
            logging.info("TSCAN Driver started, and the CAN driver is {0}".format(self.drive_type))
        else:
            logging.warning("TSCAN Driver map error, and the current CAN driver is {0}, error code is:{1}"
                            .format(self.drive_type,TSMasterAPI.tsapp_get_error_description(r)))

        # m.FAppChannelIndex = CH2  # CH2
        # m.FHWDeviceType = TS_TCP_DEVICE
        # m.FHWDeviceSubType = -1
        # m.FHWIndex = 0
        # m.FHWChannelIndex = CH2
        # set_mapping(m)

        # configure CAN channel baudrates before connection: Arb = 500K, Data = 2M
        if self.configure_baudrate['CAN_Type'] == 'CAN':
            TSMasterAPI. tsapp_configure_baudrate_can(self.ChannelIndex.value, 
                                                        self.configure_baudrate['ArbRate'], 
                                                        False, 
                                                        self.configure_baudrate['TermResistor'])
            logging.info('The currentCAN_Type is {0},ArbRate is {1}, TermResistor is {2}'
                 .format(self.configure_baudrate['CAN_Type'],self.configure_baudrate['ArbRate'],self.configure_baudrate['TermResistor']))
        elif self.configure_baudrate['CAN_Type'] == 'CANFD':
            TSMasterAPI.tsapp_configure_baudrate_canfd(self.ChannelIndex.value, 
                                                        self.configure_baudrate['ArbRate'], self.configure_baudrate['DataRate'],
                                                        TSMasterAPI.TLIBCANFDControllerType.lfdtISOCAN.value, 
                                                        TSMasterAPI.TLIBCANFDControllerMode.lfdmNormal.value, 
                                                        self.configure_baudrate['TermResistor'])
            logging.info('The currentCAN_Type is {0},ArbRate is {1}, DataRate is {2},TermResistor is {3}'
                 .format(self.configure_baudrate['CAN_Type'],self.configure_baudrate['ArbRate'],self.configure_baudrate['DataRate'],
                            self.configure_baudrate['TermResistor']))        

        logging.info('Init Done')

    def load_dbc(self,DBC_File_Path,ASupportedChannelsBased = "0"):
        TSMasterAPI.tsdb_unload_can_dbs()   # 解绑所有dbc
        self.dbchandle = c_int32(0)
        # if 0 == TSMasterAPI.tsdb_load_can_db(DBC_File_Path, "0", self.idDBC):         ##   Load DBC, Note: 加载dbc必须在app connect 之前
        if 0 == TSMasterAPI.tsdb_load_can_db(DBC_File_Path, ASupportedChannelsBased, self.dbchandle):    
            logging.info('CAN/CAN-FD database loaded success! And load dbc file at {0} ASupportedChannelsBased'.format(ASupportedChannelsBased)) 
        else:
            logging.warning('load dbc error !!!, You dbc path is : {0}'.format(DBC_File_Path))
        pass

    def RBS_Config(self,NetName,EnableNode):
        self.EnableNode = EnableNode
        (rivUseDB, rivUseLast, rivUse0) = (c_int(0), c_int(1), c_int(2)) 
        if 0 == TSMasterAPI.tscom_can_rbs_configure(False, True, True, rivUseDB):   #   configure can rbs
            logging.info('can RBS_Config success')
        else:
            logging.warning('RBS_Config error')

        #   activate everything in rbs
        # TSMasterAPI.dll.tscom_can_rbs_activate_all_networks(True, True)
        r = TSMasterAPI.dll.tscom_can_rbs_activate_network_by_name(self.ChannelIndex.value,True,NetName.encode("utf8"),False)
        if  0 == r:
            pass
        else:
            logging.warning('NetName add to rbs error: {0}---{1}'.format(NetName,TSMasterAPI.tsapp_get_error_description(r)))
        # #   activate specification in rbs
        for node in self.EnableNode:
            r = TSMasterAPI.dll.tscom_can_rbs_activate_node_by_name(self.ChannelIndex.value,True, NetName.encode("utf8"), node.encode("utf8"), True)
            if 0 == r:
                logging.info('Enable rbs node : {0}'.format(node))
            else:
                logging.warning('node add to rbs error: {0}---{1}'.format(node,TSMasterAPI.tsapp_get_error_description(r)))
        # r = TSMasterAPI.dll.tscom_can_rbs_start() #   start rbs
        # if  0 == r: 
        #     logging.info("CAN RBS is started...")
        # else:
        #     logging.warning("CAN RBS is started error:{0}".format(TSMasterAPI.tsapp_get_error_description(r)))

    def Enable_rbs_message(self,NetName,node,Message,Enalbe= True):
        r  = TSMasterAPI.dll.tscom_can_rbs_activate_message_by_name(self.ChannelIndex.value,Enalbe, NetName.encode("utf8"), node.encode("utf8"),Message.encode("utf8"), True)
        if 0 == r:
            logging.info('Enable rbs node :{0}---{1}'.format(Message,Enalbe))
        else:
            logging.warning('node add to rbs error: {0}---{1}'.format(Message,TSMasterAPI.tsapp_get_error_description(r)))
        pass

    def register_event_can_T_R(self,eventdef):
        obj = c_int32(0)
        if 0 == TSMasterAPI.tsapp_register_event_can(obj, eventdef): #   register can rx-tx event
            logging.info("CAN TX&RX callback successful")
        else:
            logging.warning("CAN TX&RX callback add error")
        return obj

    def register_event_can_T_pre(self,eventdef):
        obj = c_int32(0)
        if 0 == TSMasterAPI.tsapp_register_pretx_event_can(obj, eventdef): #   register can tx pre event
            logging.info("CAN TX Pre callback successful")
        else:
            logging.warning("CAN TX Pre callback add error")
        return obj

    def register_event_canfd_T_R(self,eventdef):
        obj = c_int32(1)
        if 0 == TSMasterAPI.tsapp_register_event_canfd(obj, eventdef): #   register canFD rx-tx event
            logging.info("CANFD TX&RX callback add successful")
        else:
            logging.warning("CANFD TX&RX callback add error")     
        return obj

    def register_event_canfd_T_pre(self,eventdef):
        obj = c_int32(0)
        if 0 == TSMasterAPI.tsapp_register_pretx_event_canfd(obj, eventdef): #   register canFD tx pre event
            logging.info("CANFD TX Pre callback add successful")
        else:
            logging.warning("CANFD TX Pre callback add error")     
        return obj

    def register_event_canfd_T_pre2(self,eventdef):
        obj = c_int32(1)
        if 0 == TSMasterAPI.tsapp_register_pretx_event_canfd(obj, eventdef): #   register canFD tx pre event
            logging.info("CANFD2 TX Pre callback add successful")
        else:
            logging.warning("CANFD2 TX Pre callback add error")     
        return obj
    
    def connect_application(self):
        # connect application
        r = TSMasterAPI.tsapp_connect()
        if  0==r:
            logging.info("TSMasterCDemo application connected, communication starts here...") 
        else:
            logging.warning("TSMasterCDemo application connected error :{0} ".format(TSMasterAPI.tsapp_get_error_description(r)))

        TSMasterAPI.tsfifo_enable_receive_fifo()    # 硬件开启成功后,开启fifo接收

        # 是否使能总线数据统计
        r = TSMasterAPI.dll.tsapp_enable_bus_statistics(True)
        if  0==r:
            logging.info("enable_bus_statistics...") 
        else:
            logging.warning("enable_bus_statistics error :{0}".format(TSMasterAPI.tsapp_get_error_description(r)))
        
    def dis_connect_application(self):
        #   [17] unregister pre-tx event
        # unregister_pretx_events_canfd(idpretx)
        # print("Unregister pretx event succeed")

        #   stop rbs
        if  0 == TSMasterAPI.dll.tscom_can_rbs_stop():
           logging.info("CAN RBS stopped")

        if 0 == TSMasterAPI.tsdb_unload_can_dbs():
            logging.info("unload_can_dbs")
        
        if 0 == TSMasterAPI.tsapp_disconnect():
            logging.info("TSMasterCDemo application disconnected")

        # TSMasterAPI.tsapp_del_application(APP_NAME)

        # if 0 ==TSMasterAPI.finalize_lib_tsmaster():
        #     logging.info("TSMaster dll finalized")

    def start_rbs(self):
        r = TSMasterAPI.dll.tscom_can_rbs_start() #   start rbs
        if  0 == r: 
            logging.info("CAN RBS is started...")
        else:
            logging.warning("CAN RBS is started error:{0}".format(TSMasterAPI.tsapp_get_error_description(r)))

    def stop_rbs(self):
        #   stop rbs
        if  0 == TSMasterAPI.dll.tscom_can_rbs_stop():
           logging.info("CAN RBS stopped")

    
    def TransmitData(self,ID,FrameData,CAN_Type = 'CAN', isPrint = False):
        self.FrameData = FrameData
        if CAN_Type == 'CANFD':
            self.cFD.FIdxChn = self.ChannelIndex.value
            self.cFD.FIdentifier = ID
            self.cFD.FProperties = 1       # 定义canfd数据类型  1:FD标准帧 5:FD扩展帧
            self.cFD.FFDProperties = 0x1   # 0:普通can数据帧 1：canfd数据帧
            self.cFD.FDLC = 15
            if len(self.FrameData) < 64:
                self.FrameData = self.FrameData +( [0] * (64 - len(FrameData)) )
            for i in range(len(self.FrameData)):
                self.cFD.FData[i] = self.FrameData[i]
            # TSMasterAPI.tsapp_transmit_canfd_async(self.cFD)    
            TSMasterAPI.dll.tsapp_transmit_canfd_async(byref(self.cFD)) # transmit this CANFD frame asynchrnously
            if isPrint:
                sendstr = binascii.b2a_hex(bytearray(FrameData), ' ')
                logging.info(f'发送ID = 0x{ID:03X}, 数据= [{sendstr}]')

            pass
        else:
            self.c.FIdxChn = self.ChannelIndex.value
            self.c.FIdentifier = ID
            self.c.FProperties = 1
            self.c.FDLC = 8
            for i in range(len(self.FrameData)):
                self.c.FData[i] = self.FrameData[i]
            # TSMasterAPI.tsapp_transmit_can_async(self.c)    
            TSMasterAPI.dll.tsapp_transmit_can_async(byref(self.c)) # transmit this classical CAN frame asynchrnously
            if isPrint:
                sendstr = binascii.b2a_hex(bytearray(FrameData), ' ')
                logging.info(f'发送ID = 0x{ID:03X}, 数据= [{sendstr}]')

    def TS_delay(self,delaytime):
        time.sleep(delaytime/1000)
    
    def set_read_buffersize(self,size=4096):
        self.bufferszie = copy.copy(c_uint32(size))

    def read_frame(self, isPrint = False):
        # bufferszie = self.bufferszie
        bufferszie = copy.copy(c_uint32(4096))
        self.read_frame_ALl_data = self.read_frame_ALl_data.drop(index=self.read_frame_ALl_data.index)
        CAN_data = None
        # if q.qsize()>0:
        #     for i in range(q.qsize()):
        #         self.read_frame_ALl_data = pd.concat([self.read_frame_ALl_data,q.get().to_frame().T],ignore_index=True)

        if self.configure_baudrate['CAN_Type'] == 'CAN':
            self.c_buffer = []
            for i in range(10000):
                c = TSMasterAPI.TLIBCAN()
                self.c_buffer.append(c)
            data = POINTER(TSMasterAPI.TLIBCAN * len(self.c_buffer))((TSMasterAPI.TLIBCAN * len(self.c_buffer))(*self.c_buffer))
            if 0 == TSMasterAPI.dll.tsfifo_receive_can_msgs(data, byref(bufferszie), self.ChannelIndex.value, TSMasterAPI.READ_TX_RX_DEF.ONLY_RX_MESSAGES):
                for i in range(bufferszie.value):
                    self.c_buffer[i] = data.contents[i]
                    CAN_data = pd.Series({'AIdxChn':data.contents[i].FIdxChn,
                                            'AIsTx':(data.contents[i].FProperties)&0x01,
                                            'AIsRemote':(data.contents[i].FProperties)&0x02,
                                            'AIsExtended':(data.contents[i].FProperties)&0x04,
                                            'AIsError':(data.contents[i].FProperties)&0x80,
                                            'ADLC':data.contents[i].FDLC,
                                            'AIdentifier':data.contents[i].FIdentifier,
                                            'ATimeUs':data.contents[i].FTimeUs/1000000.0,
                                            'ADatas':data.contents[i].FData,
                                            })
                    self.read_frame_ALl_data = pd.concat([self.read_frame_ALl_data,CAN_data.to_frame().T],ignore_index=True)
            else:
                logging.warning('read CAN error')                
        elif self.configure_baudrate['CAN_Type'] == 'CANFD':
            self.cFD_buffer=[]
            for i in range(10000):
                cfd = TSMasterAPI.TLIBCANFD()
                self.cFD_buffer.append(cfd)
            data = POINTER(TSMasterAPI.TLIBCANFD * len(self.cFD_buffer))((TSMasterAPI.TLIBCANFD * len(self.cFD_buffer))(*self.cFD_buffer))
            
            if 0 == TSMasterAPI.dll.tsfifo_receive_canfd_msgs(data, byref(bufferszie), self.ChannelIndex.value, TSMasterAPI.READ_TX_RX_DEF.ONLY_RX_MESSAGES):
                for i in range(bufferszie.value):
                    self.cFD_buffer[i] = data.contents[i]
                    CAN_data = pd.Series({'AIdxChn':data.contents[i].FIdxChn,
                                            'AIsTx':(data.contents[i].FProperties)&0x01,
                                            'AIsRemote':(data.contents[i].FProperties)&0x02,
                                            'AIsExtended':(data.contents[i].FProperties)&0x04,
                                            'AIsError':(data.contents[i].FProperties)&0x80,
                                            'ADLC':data.contents[i].FDLC,
                                            'AIdentifier':data.contents[i].FIdentifier,
                                            'ATimeUs':data.contents[i].FTimeUs/1000000.0,
                                            'ADatas':data.contents[i].FData,
                                            'FFDProperties':data.contents[i].FFDProperties
                                            })
                    # FProperties:Byte  //default 0 , masked status:
                    # [7] 0-normal frame 1-normal frame 
                    # [6] 0-not logged  1-already  logged
                    # [5-3]  tbd
                    # [2] 0-std frame  1-Extended frame
                    # [1] 0-data frame  1-remote frame
                    # [0] fir : 0-RX 1-TX
                       
                    # 'AIsEDL':0,
                    # 'AIsBRS':ACAN.contents.FFDProperties,
                    # 'AIsESI':0,
                                        
                    self.read_frame_ALl_data = pd.concat([self.read_frame_ALl_data,CAN_data.to_frame().T],ignore_index=True)
            else:
                logging.warning('read CANFD error')
        if isPrint:        
            logging.info('in read step : Read fifo size {0} '.format(self.read_frame_ALl_data.shape[0]))
            print('in read step : Read fifo size {0} '.format(self.read_frame_ALl_data.shape[0]))
        return self.read_frame_ALl_data,bufferszie.value

    def ClearBuffer(self):
        if self.configure_baudrate['CAN_Type'] == 'CAN':
            if 0 ==TSMasterAPI.tsfifo_clear_can_receive_buffers(self.ChannelIndex.value):
                pass
            else:
                logging.warning('clear CAN buffer error')
        elif self.configure_baudrate['CAN_Type'] == 'CANFD':
            if 0 == TSMasterAPI.tsfifo_clear_canfd_receive_buffers(self.ChannelIndex.value):
                pass 
            else:
                logging.warning('clear CANFD buffer error')

        # # print('qsize {0} will be clear'.format(q.qsize()))
        # q.queue.clear()
        # print('In fush step : Read fifo size {0} '.format(self.read_frame_ALl_data.shape[0]))
        self.read_frame_ALl_data = self.read_frame_ALl_data.drop(index=self.read_frame_ALl_data.index)

    def send_CANFrame_Cycle(self,ID,FrameData,cycletime,cycle_CAN_Type='CAN'):
        self.FrameData = FrameData
        cycle_ref = None
        if cycle_CAN_Type == 'CANFD':
            cycle_ref = TSMasterAPI.TLIBCANFD()
            # self.c = TSMasterAPI.TLIBCAN()
            cycle_ref.FIdxChn = self.ChannelIndex.value
            cycle_ref.FIdentifier = c_int32(ID)
            cycle_ref.FProperties = c_uint8(1)       # 定义canfd数据类型  1:FD标准帧 5:FD扩展帧
            cycle_ref.FFDProperties = 0x1   # 0:普通can数据帧 1：canfd数据帧
            cycle_ref.FDLC = 15
            if len(self.FrameData) < 64:
                self.FrameData = self.FrameData +( [0] * (64 - len(FrameData)) )
            for i in range(len(self.FrameData)):
                cycle_ref.FData[i] = self.FrameData[i]
            r = TSMasterAPI.tsapp_add_cyclic_msg_canfd(cycle_ref, cycletime) # send periodically
            if 0 == r:
                logging.info('tsapp_add_cyclic_msg_canfd:----'.format(hex(ID)))
            else:
                logging.warning('tsapp_add_cyclic_msg_canfd error: {0}'.format(TSMasterAPI.tsapp_get_error_description(r)))
        elif cycle_CAN_Type == 'CAN':
            cycle_ref = TSMasterAPI.TLIBCAN()
            cycle_ref.FIdxChn = c_uint8(self.ChannelIndex.value)
            cycle_ref.FIdentifier = c_int32(ID)
            cycle_ref.FProperties = c_uint8(1)
            cycle_ref.FDLC = c_uint8(8)
            for i in range(len(self.FrameData)):
                cycle_ref.FData[i] = c_uint8(self.FrameData[i])
            r = TSMasterAPI. dll.tsapp_add_cyclic_msg_can(byref(cycle_ref), c_float(cycletime))  # send periodically
            if 0 == r:
                logging.info('tsapp_add_cyclic_msg_can: {0}'.format(hex(ID)))
            else:
                logging.warning('tsapp_add_cyclic_msg_can error: {0}'.format(TSMasterAPI.tsapp_get_error_description(r)))          
        return cycle_ref

    def stop_FrANFrame_Cycle(self,CAN_ref,cycle_CAN_Type='CAN'):
        if cycle_CAN_Type == 'CANFD':
            TSMasterAPI.tsapp_del_cyclic_msg_canfd(CAN_ref)
        else:
            TSMasterAPI.tsapp_del_cyclic_msg_can(CAN_ref)
        pass

    def read_db_signal(self, netname, nodename, msgName, signalname):
        """
        从CAN数据库读取信号值
        参数:
            netname: 网络名称
            nodename: 节点名称 
            msgName: 报文名称
            signalname: 信号名称
        返回:
            成功: 信号值(float)
            失败: None
        """
        try:
            valuehandle = c_double(0)
            ret = TSMasterAPI.dll.tscom_can_rbs_get_signal_value_by_element(
                self.ChannelIndex.value,
                netname.encode("utf8"),
                nodename.encode("utf8"),
                msgName.encode("utf8"),
                signalname.encode("utf8"),
                byref(valuehandle))
            
            if ret == 0:
                logging.info(f'读取信号成功: {netname}--{nodename}--{msgName}--{signalname}: {valuehandle.value}')
                return valuehandle.value
            else:
                logging.warning(f'读取信号失败: {netname}--{nodename}--{msgName}--{signalname}, 错误码: {ret}')
                return None
        except Exception as e:
            logging.error(f'读取信号异常: {netname}--{nodename}--{msgName}--{signalname}, 错误: {str(e)}')
            return None

    def write_db_signal(self,netname,nodename,msgName,signalname,value):
        valuehandle = c_double(value)
        if 0 == TSMasterAPI.dll.tscom_can_rbs_set_signal_value_by_element(self.ChannelIndex.value,
                                                                                netname.encode("utf8"),
                                                                                nodename.encode("utf8"),
                                                                                msgName.encode("utf8"),
                                                                                signalname.encode("utf8"),
                                                                                valuehandle):
            logging.info('tscom_can_rbs_set_signal_value_by_element:{0}--{1}--{2}--{3}: {4}'.format(netname,nodename,msgName,signalname,value))  
        else:
            logging.warning('tscom_can_rbs_set_signal_value_by_element error :{0}-{1}-{2}-{3}'.format(netname,nodename,msgName,signalname))                                                                        

    def tsapp_start_logging(self,filename: str): # 开始录制报文
        r = TSMasterAPI.dll.tsapp_start_logging(filename.encode("utf8"))
        if 0 == r:
            logging.info('start_logging Successful :{0}  '.format(r))
        else:
             logging.warning('start_logging error : {0}'.format(TSMasterAPI.tsapp_get_error_description(r)))
        return r

    def tsapp_stop_logging(self):   # 停止录制报文
        r = TSMasterAPI.dll.tsapp_stop_logging()
        return r


    def get_fps(self,ID,CAN_Type='CAN'):
        AIdentifier = c_int32(ID)
        FPS = c_int32(0)
        if CAN_Type =='CAN':
            r = TSMasterAPI.dll.tsapp_get_fps_can(self.ChannelIndex.value, AIdentifier, byref(FPS))
        elif CAN_Type =='CANFD':
            r = TSMasterAPI.dll.tsapp_get_fps_canfd(self.ChannelIndex.value, AIdentifier, byref(FPS))
        if 0 == r:
            logging.info('get {0} FPS : {1}/s  '.format(ID,FPS.value))
        else:
            logging.warning('Get ID FPS error: {0}'.format(TSMasterAPI.tsapp_get_error_description(r)))
        return FPS.value

    def get_bus_statistics(self,cbsBusLoad = 0):
            # typedef enum {
            #              cbsBusLoad = 0, cbsPeakLoad, cbsFpsStdData, cbsAllStdData,
            #                 cbsFpsExtData, cbsAllExtData, cbsFpsStdRemote, cbsAllStdRemote,
            #                 cbsFpsExtRemote, cbsAllExtRemote, cbsFpsErrorFrame, cbsAllErrorFrame	
            #               } TLIBCANBusStatistics
        status = c_int8(0)
        c_cbsBusLoad = c_int8(cbsBusLoad)
        r = TSMasterAPI.dll.tsapp_get_bus_statistics(TSMasterAPI.TLIBApplicationChannelType.APP_CAN.value,self.ChannelIndex.value,c_cbsBusLoad,byref(status))
        if 0 == r:
            logging.info('get_bus_statistics:{0}  '.format(status.value))
        else:
             logging.warning('get_bus_statistics: {0}'.format(TSMasterAPI.tsapp_get_error_description(r)))
        return status.value

    def send_CMD_Shell(self,cmdID,cmdstr):
        if len(cmdstr)%7 == 0:
            cmd_array = list(bytearray(cmdstr.encode('ascii')))
        else:
            cmd_array = list(bytearray(cmdstr.encode('ascii'))) + [0x00]*(7-len(cmdstr)%7)
        cmd_array_2D = np.array(cmd_array).reshape(-1,7)
        index_array = np.arange(cmd_array_2D.shape[0])
        send_array = np.insert(cmd_array_2D,0,index_array,axis=1)
        first_frame = [0x88] + [len(cmdstr)>>8] + [(len(cmdstr))%255]+[0,0,0,0,0]
        last_frame = [0xFF] + [0,0,0,0,0,0,0]
        self.TransmitData(cmdID,first_frame)
        for each_data in send_array:
            self.TransmitData(cmdID,each_data)
        self.TransmitData(cmdID,last_frame)
        logging.info('Send string is: {}'.format(cmdstr))

    def read_CMD_Shell(self,cmdID,cmdstr):
        cmd = cmdstr[4:7]
        string = cmdstr[8:]
        start_valid = False
        stop_valid = False
        replay = []
        ALl_data = pd.DataFrame()  
        Cal_data = None
        replay_value = 0
        # if q.qsize()>0:
        try:
            if True:
                # for i in range(q.qsize()):
                #     ALl_data = pd.concat([ALl_data,q.get().to_frame().T],ignore_index=True)

                ALl_data , buffer_size = self.read_frame()
                Cal_data = ALl_data[ALl_data['AIdentifier']==cmdID]

                for i in Cal_data.index: #search first frame
                    if Cal_data.loc[i].ADatas[0] ==0x88:
                        start_valid = True
                        start = i
                        cmd_len = ((Cal_data.loc[i].ADatas[1]) << 8) + Cal_data.loc[i].ADatas[2]
                        break
                    else:
                        start_valid = False
                for i in Cal_data.index:#search last frame
                    if Cal_data.loc[i].ADatas[0] ==0xFF:
                        stop_valid = True
                        stop = i
                        break
                    else:
                        stop_valid = False
                if start_valid and stop_valid: #search the replay value
                    new = Cal_data.iloc[Cal_data.index.get_loc(start)+1:Cal_data.index.get_loc(stop),:]
                    for index, row in new.iterrows():
                        replay += row.ADatas[1:8]
                    last_value = replay[:cmd_len]
                    value_str = bytes(last_value).decode('ascii')
                    if cmdstr[0:7] == 'profile':
                        replay_value = value_str
                    elif cmd == 'get':
                        replay_value = re.findall('(?<={0} ).*$'.format(string),value_str)[0]
                    else:
                        replay_value = value_str
                else:
                    replay_value = 'done'
            else:
                replay_value = 'False'
            logging.info('Recieve string is: {}'.format(replay_value))
        except:
            replay_value = 'False'
            logging.warning('read_CMD_Shell error')
        return replay_value

    def sendAndread_CMD_Shell(self,cmdID=0x114,cmdstr='cmd',delaytime=100):
        self.ClearBuffer()
        self.send_CMD_Shell(cmdID,cmdstr)
        self.TS_delay(delaytime)
        return self.read_CMD_Shell(cmdID,cmdstr)

    def parse_dbc(self):
        self.dbc_map = []
        r,Node_List_Count = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle,DB_Variable.DT_INT_Node_List_Count,-1,-1)
        if 0 == r:
            Node_List_Count_value = int(Node_List_Count)
            for i in range(Node_List_Count_value):
                node_map = {}
                TX_msg_struct_array = []
                RX_msg_struct_array = []
                FDTX_msg_struct_array = []
                FDRX_msg_struct_array = []
                TX_sig_struct_array =[]
                RX_sig_struct_array = []
                msg_struct_dict =['type','len','ID','period','name','comment','unknow1','unknow2']
                FDmsg_struct_dict =['type','len','ID','period','name','comment','unknow1','unknow2']  
                sig_struct_dict =['ID','unknow1','unknow2','comment','unknow3','unknow4','Start','len',
                                    'factory','offset','default','max ','min','name','unknow5','unknow6','unknow7','unknow8'] 

                r, node_map['node_name'] = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_STR_Node_List_Name, i, -1)
                r, node_map['node_address'] = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_Address, i, -1)
                r, node_map['node_comment'] = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_STR_Node_List_Comment, i, -1)

                r, node_TX_Msg_Count = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_TX_CAN_Message_List_Count, i, -1)
                TxCAN = int(node_TX_Msg_Count)
                r, node_RX_Msg_Count = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_RX_CAN_Message_List_Count, i, -1)
                RxCAN = int(node_RX_Msg_Count)

                r, node_FDTX_Msg_Count = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_TX_FD_Message_List_Count, i, -1)
                TxCANFD = int(node_FDTX_Msg_Count)
                r, node_FDRX_Msg_Count = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_RX_FD_Message_List_Count, i, -1)
                RxCANFD = int(node_FDRX_Msg_Count) 

                r, Tx_signal_list = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_TX_Signal_List_Count, i, -1)
                mTxSgn = int(Tx_signal_list)
                r, Rx_signal_list = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_RX_Signal_List_Count, i, -1)
                mRxSgn = int(Rx_signal_list)

                # for each tx rx CAN message or signal
                for j in range(TxCAN):
                    r, TX_msg_index = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_TX_CAN_Message_List_Message_Index, i, j)
                    if 0 ==r:
                        r, s = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_STR_CAN_Message_List_Struct, int(TX_msg_index), -1)
                        if 0 == r :
                            TX_msg_struct_array.append(dict(zip(msg_struct_dict,s.split(b',')[:len(msg_struct_dict)])))
                node_map['TX_msg_struct'] = TX_msg_struct_array

                for j in range(RxCAN):
                    r, RX_msg_index = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_RX_CAN_Message_List_Message_Index, i, j)
                    if 0 ==r:
                        r, s = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_STR_CAN_Message_List_Struct, int(RX_msg_index), -1)
                        RX_msg_struct_array.append(dict(zip(msg_struct_dict,s.split(b',')[:len(msg_struct_dict)])))
                node_map['RX_msg_struct'] = RX_msg_struct_array
                
                for j in range(TxCANFD):
                    r, FDTX_msg_index = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_TX_FD_Message_List_Message_Index, i, j)
                    if 0 ==r:
                        r, s = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_STR_CANFD_Message_List_Struct, int(FDTX_msg_index), -1)
                        if 0 == r :
                            FDTX_msg_struct_array.append(dict(zip(FDmsg_struct_dict,s.split(b',')[:len(FDmsg_struct_dict)])))
                node_map['FDTX_msg_struct'] = FDTX_msg_struct_array

                for j in range(RxCANFD):
                    r, FDRX_msg_index = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_RX_FD_Message_List_Message_Index, i, j)
                    if 0 ==r:
                        r, s = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_STR_CANFD_Message_List_Struct, int(FDRX_msg_index), -1)
                        if 0 ==r:
                            FDRX_msg_struct_array.append(dict(zip(FDmsg_struct_dict,s.split(b',')[:len(FDmsg_struct_dict)])))
                node_map['FDRX_msg_struct'] = FDRX_msg_struct_array

                for j in range(mTxSgn):
                    r, TX_sig_index = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_TX_Signal_List_Signal_Index, i, j)
                    if 0 ==r:
                        r, s = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_STR_Signal_List_Struct, int(TX_sig_index), -1)
                        if 0 ==r:
                            TX_sig_struct_array.append(dict(zip(sig_struct_dict,s.split(b',')[:len(sig_struct_dict)])))
                node_map['TX_sig_struct'] = TX_sig_struct_array

                for j in range(mRxSgn):
                    r, RX_sig_index = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_RX_Signal_List_Signal_Index, i, j)
                    if 0 ==r:
                        r, s = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_STR_Signal_List_Struct, int(RX_sig_index), -1)
                        if 0 ==r:
                            RX_sig_struct_array.append(dict(zip(sig_struct_dict,s.split(b',')[:len(sig_struct_dict)])))
                node_map['RX_sig_struct'] = RX_sig_struct_array

                self.dbc_map.append(node_map)

        else:
            logging.warning('tsdb_get_can_db_info --- DT_INT_Node_List_Count: {0}'.format(TSMasterAPI.tsapp_get_error_description(r)))

        return self.dbc_map
        

class TSCAN_UDS(object):
    def __init__(self,ChannelIndex = TSMasterAPI.CHANNEL_INDEX.CHN1, ASupportFD = 0, AMaxdlc=8, 
                reqID  = 0x72c, ARequestIDIsStd=True,
                resID  = 0x73c, resIsStd =True,
                AFctID = 0x7DF, fctIsStd =True,
                p2_extended = 5000,p2_timeout = 2500,
                s3_clienttime = 3000,s3_servertime = 5000):
        self.ChannelIndex = ChannelIndex
        self.ASupportFD = ASupportFD
        self.AMaxdlc= AMaxdlc
        self.reqID  = reqID
        self.ARequestIDIsStd = ARequestIDIsStd
        self.resID  = resID
        self.resIsStd = resIsStd
        self.AFctID = AFctID
        self.fctIsStd = fctIsStd
        self.p2_extended = p2_extended
        self.p2_timeout = p2_timeout
        self.s3_clienttime = s3_clienttime
        self.s3_servertime = s3_servertime

        self.init_UDS()

    def init_UDS(self):
        self.udsHandle = c_byte(0)
        r = TSMasterAPI.dll.tsdiag_can_create(byref(self.udsHandle), self.ChannelIndex.value, c_byte( self.ASupportFD), c_byte(self.AMaxdlc), 
                                        self.reqID,c_bool(self.ARequestIDIsStd),self.resID,c_bool(self.resIsStd),self.AFctID,c_bool(self.fctIsStd))
        if 0 == r:
            logging.info('UDS Creat successful, The udsHandle is : {0}'.format(self.udsHandle) )
        else:
            logging.warn('UDS Creat error: {0}'.format(TSMasterAPI.tsapp_get_error_description(r)) )
        TSMasterAPI.dll.tsdiag_set_p2_extended(self.udsHandle,c_int32(self.p2_extended))
        TSMasterAPI.dll.tsdiag_set_p2_timeout(self.udsHandle,c_int32(self.p2_timeout))
        TSMasterAPI.dll.tsdiag_set_s3_clienttime(self.udsHandle,c_int32(self.s3_clienttime))
        TSMasterAPI.dll.tsdiag_set_s3_servertime(self.udsHandle,c_int32(self.s3_servertime))

    def req_and_res_can(self, AReqDataArray, AReqDataSize,enable_print = True):

        self.AReqdata = (c_uint8*5000)()
        self.AResSize = c_int(5000)
        self.AResponseDataArray = (c_uint8*5000)() 

        sendstr = None
        readstr = None

        for index,datavalue in enumerate(AReqDataArray):
            self.AReqdata[index] = c_uint8(datavalue)

        ResponseDataArray = []
        sendstr = binascii.b2a_hex(bytearray(AReqDataArray),' ')

        #print sent data
        if enable_print:
            logging.info('Send UDS ID : [0x{0:X}]'.format(self.reqID))
            logging.info('Send UDS request size :{0} ---,the send data are <<<{1}>>>'.format(AReqDataSize,sendstr))

        for i in range(1):
            r  = TSMasterAPI.tstp_can_request_and_get_response(self.udsHandle, self.AReqdata, AReqDataSize, self.AResponseDataArray , self.AResSize)
            if 0 == r and self.AResSize.value != 0:
                for i in range(self.AResSize.value):
                    ResponseDataArray.append(self.AResponseDataArray[i])
                if enable_print:
                    readstr = binascii.b2a_hex(bytearray(ResponseDataArray),' ')
                    logging.info('Read UDS reponse size :{0} ---,the read data are <<<{1}>>>\n'.format(self.AResSize.value,readstr))
                break
            else:
                logging.warning('req_and_res_can error: '+ TSMasterAPI.tsapp_get_error_description(r)+'\n')
            #     self.UDS_can_delete()
            #     self.init_UDS()
            #     time.sleep(1)
            #     logging.warning('time delay 1s')
            #     logging.warning('UDS Reopen')

        return ResponseDataArray , self.AResSize.value

    def search_DTC(self, DTC_CMD,expect_DTC,timeout=5):
        start_time = time.time()
        Find_DTC = False
        rep_value = []
        while( (time.time()-start_time) < timeout):
            rep_value,rep_size = self.req_and_res_can(DTC_CMD,len(DTC_CMD),enable_print= False)
            reponse_np = np.array(rep_value)[3:].reshape((-1,4))
            for data in reponse_np.tolist():
                if expect_DTC == data:
                    Find_DTC = True
                    break
                else:
                    Find_DTC = False
            if Find_DTC:
                break
        sendstr = binascii.b2a_hex(bytearray(DTC_CMD),' ')    
        totle_time = time.time()-start_time
        all_reponse = binascii.b2a_hex(bytearray(rep_value),' ')
        logging.info('Read DTC by CMD:{0}---,DTC [{4}] had found {1}---,Totle used time {2} ---, The All reponse are {3} '.format(
            sendstr,Find_DTC,totle_time,all_reponse, binascii.b2a_hex(bytearray(expect_DTC), ' ')))
        
        return Find_DTC,totle_time,rep_value

    def uds_session_control(self,ASubSession: c_byte):
        r = TSMasterAPI.dll.tsdiag_can_session_control(self.udsHandle, ASubSession)
        if 0 == r:
            logging.info('session_control send [ {0} ] successful  '.format(ASubSession))
        else:
            logging.warning('session_control error: {0}'.format(TSMasterAPI.tsapp_get_error_description(r)))
        return r

    def uds_routine_control(self,ARoutineControlType: c_byte,ARoutintID: c_uint16):
        r = TSMasterAPI.dll.tsdiag_can_routine_control(self.udsHandle, ARoutineControlType, ARoutintID)
        if 0 == r:
            logging.info('session_control send [ {0} ] - [ {1} ] successful  '.format(str(ARoutineControlType),str(ARoutintID)))
        else:
            logging.warning('session_control error: {0}'.format(TSMasterAPI.tsapp_get_error_description(r)))
        return r

    def uds_security_access_request_seed(self,ALevel: c_int32):
        ARecSeed = []
        AResSize = c_int(100)
        AResponseDataArray = (c_uint8*100)()
        r = TSMasterAPI.dll.tsdiag_can_security_access_request_seed(self.udsHandle, 
                                            ALevel, AResponseDataArray, byref(AResSize))   
        if 0 == r:
            for i in range(AResSize.value):
                ARecSeed.append(AResponseDataArray[i])
            logging.info('session_control send  successful  ')
        else:
            logging.warning('security_access_request_seed: {0}'.format(TSMasterAPI.tsapp_get_error_description(r)))
        return ARecSeed

    def UDS_can_delete(self):
        r = TSMasterAPI.dll.tsdiag_can_delete(self.udsHandle)
        if 0 == r:
            logging.info(f'UDS_can{self.udsHandle}_delete successful')
        else:
            logging.warning(f'UDS_can{self.udsHandle}_delete error:{0}'.format(TSMasterAPI.tsapp_get_error_description(r)))


class combineDownload(object):
    def __init__(self) -> None:
        pass

    def parse_file(self,file_path):
        self.file_type = os.path.splitext(file_path)[-1]
        self.binfile_handle = bincopy.BinFile()
        if(self.file_type == '.hex' or self.file_type == '.HEX'):
            with open(file_path, 'r') as fin:
                self.binfile_handle.add_ihex(fin.read())
        if(self.file_type == '.bin' or self.file_type == '.BIN'):
            with open(file_path, 'rb') as fin:
                self.binfile_handle.add_binary(fin.read())
        if(self.file_type == '.s19'):
            with open(file_path, 'r') as fin:
                self.binfile_handle.add_srec(fin.read())
        logging.info('The file info is:  {0}'.format(file_path,self.binfile_handle.info()) )
        # logging.info(binfile_handle.segments())  #All data
        return self.binfile_handle.segments

    def download(self,candriver,file_path,start_add=0x0,size=0x0):
        download_data =[]
        self.parse_file(file_path)
        for index,segment in enumerate(self.binfile_handle.segments):
            if(self.file_type == '.bin' or self.file_type == '.BIN'):
                start_address = start_add
                segment_size = size
            else:
                start_address = segment.minimum_address
                segment_size = segment.maximum_address - segment.minimum_address
                
            # 34 Server,Request download
            Request_download_CMD = [0x34,00,0x44] + \
                                    [(start_address>>24) & 0xFF] + [(start_address>>16) & 0xFF] + [(start_address>>8) & 0xFF] + [(start_address) & 0xFF] +\
                                    [(segment_size>>24) & 0xFF] + [(segment_size>>16) & 0xFF] + [(segment_size>>8) & 0xFF] + [(segment_size) & 0xFF]
            rep_value,rep_size = candriver.req_and_res_can(Request_download_CMD,len(Request_download_CMD),enable_print= False)

            # 36 Server, start download
            download_data = download_data + list(segment.data)
            download_data_CMD = [0x36,index] + list(segment.data)
            rep_value,rep_size = candriver.req_and_res_can(download_data_CMD,len(download_data_CMD),enable_print= False)

        # 37 Server, stop download
        data_37,rep_size = candriver.req_and_res_can([0x37],1,enable_print= False)

        return download_data,data_37


class HIL_Obj(Thread):
    def __init__(self,send_ref:TSCAN):
        Thread.__init__(self)
        self.all_frame = []
        self.warning_data = []
        self.last_warninh_data = None

        self.CAN_ref = send_ref
        
    def open(self,path = './data/autosave_145924326_RawTarget.csv'):
        logging.info('parse obj file start......, The file if from : {0}'.format(path))
        with open(path) as f:
             reader=csv.reader(f)
             row_num = 0
             frame_data = []
             frame = {}
             for index, row in enumerate(reader):
                 if row[0] == 'START': 
                     Frame_flag = True
                     Frame_num = int(row[1].split(':',1)[1])
                     Frame_type = row[2].split(':',1)[1]
                     row_num =  index
                 if row[0] == 'END': 
                     Frame_flag = False
                     frame['Frame_num'] = Frame_num
                     frame['Frame_type'] = Frame_type
                     frame['Frame_num_total'] = int(row[1].split(':',1)[1])
                     frame['data'] = frame_data
                     self.all_frame.append(frame)
                     frame_data = []
                     frame = {}
                 if Frame_flag:
                     if row[3]!= '' :
                        frame_data.append(np.array(row).astype(float))
                 if index == row_num + 1 :
                    pass
                 if index == row_num + 2 :
                    pass
        logging.info('Parse over')
        self.all_frame = self.all_frame

        return self.all_frame

    def obj_sent(self):
        N = 0

        # enter debug mode
        self.CAN_ref.TransmitData((0x30<<4)+N, [0x31,0x58,0xAF,0xFF,0xFF,0xFF,0xFF,0xFF],'CAN')
        self.CAN_ref.TransmitData((0x20<<4)+N, [0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00],'CAN')
        
        # for index, data in enumerate(all_frame) :
        for data in self.all_frame :    
            start = time.time()
            VehicleSpeedInput = int(data['data'][0][6] * 100)
            yaw_rate = int(data['data'][0][16] * 100)
            obj_num = data['Frame_num_total']
            timeInterval = int(data['data'][0][12])
            if data['Frame_type'] == 'l_bsd':
                N = 4
                pass
            elif data['Frame_type'] == 'r_bsd':
                N = 5
                pass
            # Send vehicle info
            self.CAN_ref.TransmitData(0x3F5, [0x00,0x00,0x00,0x00,0x00,0x00,((VehicleSpeedInput&0xFFFF) >> 8),(VehicleSpeedInput&0xFF)],'CAN')
            self.CAN_ref.TransmitData(0x3F6, [0x00,0x00,0x00,0x00,((yaw_rate>>8) & 0xFF),(yaw_rate&0xFF),0x00,0x00],'CAN')
            # Send Header
            self.CAN_ref.TransmitData((0x60<<4)+N, [obj_num,0x00,0x00,0x20,0x00,0x00,0x00,0x00],'CAN')
            
            #[ID,Range,Velocity,Angle,SNR,Kstate,Vehicle_Speed,X_Lateral,Y_Longitudinal,
            # X_Speed,Y_Speed,Radius,timeInterval,isUse,cntCandiTrk,noisePtr,yaw_rate]
            for index,raw_detail in enumerate(data['data']):
                self.CAN_ref.TransmitData((0x71<<4)+N, [int(raw_detail[0]),
                                            ( int(raw_detail[1]*20) & 0x1FFF) >> 5 ,
                                            ((int(raw_detail[1]*20) & 0x1F  ) << 3) + ((int(raw_detail[2]*10)&0x7FF)>>8),
                                            ( int(raw_detail[2]*10) & 0xFF  ),
                                            ( int(raw_detail[3]*4)  & 0x3FF ) >> 2,
                                            ((int(raw_detail[3]*4)  & 0x03  ) << 6) + ((int(raw_detail[7])  &0x1FF)>>3),
                                            ((int(raw_detail[7])    & 0x07  ) << 5) + 0x00,
                                              int(raw_detail[4]*2)  & 0xFF],'CAN')
                # self.TransmitData((0x71<<4)+N,[1,2,3,4,5,6,7,8],'CAN')
                pass

            # Send Stop,with time
            self.CAN_ref.ClearBuffer()
            self.CAN_ref.TransmitData((0x5F<<4)+N, [0x00,0x00,0x00,0x00,timeInterval,0x00,0x00,0x00],'CAN')
            self.CAN_ref.TS_delay(10)

            # read warning
            totle = None
            warningID = None
            obj_start = time.time()
            while time.time()-obj_start < 0.05:
                totle,buffer_size  = self.CAN_ref.read_frame()
                # print('read warning once need time  is ',time.time()-obj_start)
                if buffer_size > 0:
                    warningID = totle[totle['AIdentifier']==(0x7B<<4)+N]
                    if len(warningID) > 0:
                        self.last_warninh_data = warningID.iloc[0]['ADatas']
                        self.warning_data.append(self.last_warninh_data)
                        break
                    else:
                        self.CAN_ref.TS_delay(1)
            print('elape time is ',time.time()-start)
        pass
    
    def run(self) -> None:
        self.obj_sent()
        return super().run()

# def test():
#     for i in range(5):
#         print(threading.current_thread().name+' test ',i)
#         time.sleep(1)
# thread = threading.Thread(target=test)
# thread.start()

# retrieve application timestamp
# print("Current timestamp(s) is", app.get_timestamp() / 1000000.0)

# run main
if __name__ == "__main__":
    # import os
    # root = os.getcwd()
    # project_DBC_File_CAN = os.path.join(root, r'data\FX12_Matrix_FRM_V1_7_20220531.dbc')
    # print(project_DBC_File_CAN)
    try:
        rbs = TSCAN(drive_type = 'USE_TS_TC1013_DEVICE',   #'USE_TS_TC1014_DEVICE':USE_TS_VIRTUAL_DEVICE
                    configure_baudrate = {'CAN_Type':'CANFD','ArbRate':500,'DataRate':2000,'TermResistor':True}
                    )
        # rbs.load_dbc(project_DBC_File_CAN)
        # rbs.register_event_can_T_R(OnCANevent)
        # rbs.register_event_canfd_T_R(OnCANFDevent)
        rbs.connect_application()


        print('send frame')
        # rbs.TransmitData(0x666,[0x61,2,3,4,5,6,7,8,
        #                       0x22,2,3,4,5,6,7,8,
        #                       0x23,2,3,4,5,6,7,8,
        #                       0x24,2,3,4,5,6,7,8,
        #                       0x25,2,3,4,5,6,7,8,
        #                       0x26,2,3,4,5,6,7,8,
        #                       0x27,2,3,4,5,6,7,8,
        #                       0x28,2,3,4,5,6,7,8],'CANFD')
        # rbs.TransmitData(0x114,[0x71,2,3,4,5,6,7,8,],'CAN')
        # rbs.TransmitData(0x777,[0x81,2,3,4,5,6,7,8,],'CAN')
        # rbs.TransmitData(0x444,[0x41,2,3,4,5,6,7,8,],'CAN')

        # print('step1_wait_1000_:::::')
        # rbs.ClearBuffer()
        # rbs.TS_delay(1000)
        # rbs.read_frame()

        # print('step2__wait_2000_:::::') 
        # rbs.ClearBuffer()
        # rbs.TS_delay(2000)
        # rbs.read_frame()

        # print('step2__wait_2000_:::::') 
        # rbs.ClearBuffer()
        # rbs.TS_delay(2000)
        # rbs.read_frame()

        # print('step3__wait_3000_:::::') 
        # rbs.ClearBuffer()
        # rbs.TS_delay(3000)
        # rbs.read_frame()
        t1 = rbs.sendAndread_CMD_Shell(0x114,'profile 0',50)
        print(t1)
        t2= rbs.sendAndread_CMD_Shell(0x114,'cmd get gSmStatusMask 0 L 1',50)
        print(t2)
        # rbs.send_CMD_Shell(0x114,'cmd fsmErrInjection 4 0')
        # t3= rbs.sendAndread_CMD_Shell(0x114,'cmd fsmErrInjection 4 0',50)
        # print(t3)

        # a =rbs.send_CANFrame_Cycle(0x22,[0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88],100)
        # rbs.TS_delay(5000)
        # rbs.stop_FrANFrame_Cycle(a)


        # diag = TSCAN_UDS()
        # for i in range (1):
        #     diag.req_and_res_can(0x10, [0x03])
        # diag.UDS_can_delete()

        # obj = HIL_Obj(rbs)
        # obj.setDaemon(True)
        # obj.open()
        # obj.obj_sent()
        # obj.start()
        # obj.last_warninh_data
        # obj.warning_data

        # rbs.parse_dbc()

        rbs.dis_connect_application()

        print('Over All')
        import sys
        sys.exit(0)

    except Exception as e :
        rbs.dis_connect_application()
        import sys
        import traceback
        print(traceback.print_exc())
        sys.exit(0)
        pass
    
    except KeyboardInterrupt :
        rbs.dis_connect_application()
        import sys
        import traceback
        print(traceback.print_exc())
        sys.exit(0)
        pass
